package de.h_da.fbi.cg.pointcloud.run;

import java.io.IOException;
import java.util.HashMap;

import org.anddev.progressmonitor.ProgressMonitor;

import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;

import de.h_da.fbi.cg.pointcloud.adt.Vertex;
import de.h_da.fbi.cg.pointcloud.adt.VertexList;
import de.h_da.fbi.cg.pointcloud.parser.ply.SimplePLYParser;
import de.h_da.fbi.cg.pointcloud.parser.ply.adt.PLYConfigTransformation;
import de.h_da.fbi.cg.pointcloud.parser.ply.conf.SimplePLYConfigParser;
import de.h_da.fbi.cg.pointcloud.ui.dialog.ProgressDialog;
import de.h_da.fbi.cg.pointcloud.util.constants.Constants;

/**
 * @author Nicolas Gramlich
 * @since 15:49:47 - 11.11.2010
 */
public class StanfordBunny extends BaseApplication {
	// ===========================================================
	// Constants
	// ===========================================================

	// ===========================================================
	// Fields
	// ===========================================================

	// ===========================================================
	// Constructors
	// ===========================================================

	public static void main(final String[] args) {
		final StanfordBunny app = new StanfordBunny();
		app.start();
	}

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	protected Vector3f getStepTranslation() {
		return new Vector3f(0.2f, 0, 0);
	}

	@Override
	protected VertexList getVertexList(final ProgressDialog progressDialog, final ProgressMonitor mainProgressMonitor) throws IOException {
		final HashMap<String, PLYConfigTransformation> plyConfigTransformations = SimplePLYConfigParser.parse(BaseApplication.class.getClassLoader().getResource("bun.conf").openStream(), new ProgressMonitor(mainProgressMonitor));

		//					final String[] plyFiles = new String[] { "bun000.ply", "bun045.ply", "bun090.ply", "bun180.ply", "bun270.ply", "bun315.ply", "top2.ply", "top3.ply", "chin.ply", "ear_back.ply" };
		//					final String[] plyFiles = new String[] { "bun000.ply", "bun090.ply", "bun180.ply", "bun270.ply", "bun045.ply" };
		final String[] plyFiles = new String[] { "bun000.ply", "bun090.ply", "bun180.ply", "bun270.ply" };

		final int plyFileCount = plyFiles.length;
		final float percentPerPart = 100.0f / plyFileCount;
		final VertexList vertices = new VertexList();

		for(int i = 0; i < plyFileCount; i++) {
			final String plyFile = plyFiles[i];
			progressDialog.setLabelText("Parsing '" + plyFile + "' ...");

			/* Load PLY-File. */
			mainProgressMonitor.setSubMonitorRange((int) (percentPerPart * i), (int) (percentPerPart * (i + 1)));
			final float[] bunnyPartPointCloudVertexCoordinates = StanfordBunny.this.loadPLYFile(plyFile, new ProgressMonitor(mainProgressMonitor));

			/* Transform vertices as conf file described. */
			final PLYConfigTransformation plyConfigTransformation = plyConfigTransformations.get(plyFile);
			StanfordBunny.this.transformVertices(bunnyPartPointCloudVertexCoordinates, plyConfigTransformation.getTranslation(), plyConfigTransformation.getQuaternion());

			StanfordBunny.addVerticesToGraph(vertices, bunnyPartPointCloudVertexCoordinates);
		}
		return vertices;
	}

	// ===========================================================
	// Methods
	// ===========================================================

	private static void addVerticesToGraph(final VertexList pVertices, final float[] pVertexCoordinates) {
		for(int i = 0, j = 0; i < pVertexCoordinates.length; j++) {
			if(j % Constants.SAMPLE_RATE == 0) {
				final float x = pVertexCoordinates[i++];
				final float y = pVertexCoordinates[i++];
				final float z = pVertexCoordinates[i++];

				pVertices.add(new Vertex(x, y, z));
			} else {
				i+=3;
			}
		}
	}

	private float[] loadPLYFile(final String pPLYFile, final ProgressMonitor pProgressMonitor) throws IOException {
		return SimplePLYParser.parseAscii(BaseApplication.class.getClassLoader().getResource(pPLYFile).openStream(), pProgressMonitor);
	}

	private void transformVertices(final float[] pPointCloudVertexCoordinates, final Vector3f pTranslation, final Quaternion pQuaternion) {
		final Vector3f current = new Vector3f();

		for(int i = 0; i < pPointCloudVertexCoordinates.length; i+=3) {
			current.set(pPointCloudVertexCoordinates[i], pPointCloudVertexCoordinates[i + 1], pPointCloudVertexCoordinates[i + 2]);

			current.addLocal(pTranslation);

			pQuaternion.mult(current, current);

			pPointCloudVertexCoordinates[i + 0] = current.x;
			pPointCloudVertexCoordinates[i + 1] = -current.y;
			pPointCloudVertexCoordinates[i + 2] = current.z;
		}
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}
